//
// RS Game Framework
// Copyright © 2009 Jedd Haberstro
// jhaberstro@gmail.com
// 
// $Id:
//

#ifndef RS_REFLECTION_CLASS_HPP
#define RS_REFLECTION_CLASS_HPP

#include "rs/reflection/Attribute.hpp"
#include "rs/reflection/AttributeProperties.hpp"
#include "rs/reflection/ClassBuilderInterface.hpp"
#include "rs/reflection/Method.hpp"
#include "rs/reflection/ReflectionCenter.hpp"
#include "rs/Assert.hpp"
#include "rs/Portability.hpp"
#include <vector>
#include <map>
#include <iostream>
#include <cstring>

namespace rs
{
    namespace reflection
    {      
        class Class
        {
            friend class ReflectionCenter;
            
        private:
            
            typedef std::map< UInt32, std::vector< Constructor > > ConstructorContainer;
                        
        public:
            template< typename TClass, typename TAttributeType >
            static void SetAttributesValue(TClass& instance, Attribute const* attribute, TAttributeType value);
            
            template< typename TClass, typename TAttributeType >
            static void SetAttributesValue(TClass& instance, UInt32 index, TAttributeType value);
            
            static void SetAttributesValue(void* instance, Attribute const* attribute, void const* value, RsSize size);
            
            template< typename TClass, typename TAttributeType >
            static void GetAttributesValue(TClass& instance, Attribute const* attribute, TAttributeType& value);
            
            template< typename TClass, typename TAttributeType >
            static void GetAttributesValue(TClass& instance, UInt32 index, TAttributeType& value);
            
            static void GetAttributesValue(void* instance, Attribute const* attribute, char* value, RsSize size);
            
            Class(hidden::ClassBuilderInterface const* builder);
            
            template< typename TClassBuilder >
            Class(TClassBuilder const& cb);
            
            ~Class();
            
            void* Construct() const;
                         
            template< typename TArg > 
            void* Construct(TArg arg) const;
            
            template< typename TArg, typename TArg1 > 
            void* Construct(TArg arg, TArg1 arg1) const;
            
            template< typename TArg, typename TArg1, typename TArg2 > 
            void* Construct(TArg arg, TArg1 arg1, TArg2 arg2) const;
            
            template< typename TArg, typename TArg1, typename TArg2, typename TArg3 > 
            void* Construct(TArg arg, TArg1 arg1, TArg2 arg2, TArg3 arg3) const;
            
            template< typename TArg, typename TArg1, typename TArg2, typename TArg3, typename TArg4 > 
            void* Construct(TArg arg, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4) const;
            
            void Construct(void* dest) const;
                         
            template< typename TArg > 
            void Construct(void* dest, TArg arg) const;
            
            template< typename TArg, typename TArg1 > 
            void Construct(void* dest, TArg arg, TArg1 arg1) const;
            
            template< typename TArg, typename TArg1, typename TArg2 > 
            void Construct(void* dest, TArg arg, TArg1 arg1, TArg2 arg2) const;
            
            template< typename TArg, typename TArg1, typename TArg2, typename TArg3 > 
            void Construct(void* dest, TArg arg, TArg1 arg1, TArg2 arg2, TArg3 arg3) const;
            
            template< typename TArg, typename TArg1, typename TArg2, typename TArg3, typename TArg4 > 
            void Construct(void* dest, TArg arg, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4) const;
             
            void Destruct(void* object) const;
            
            Attribute const* GetAttribute(UInt32 index) const;
            
            Attribute const* GetAttributeViaName(Char8 const* name) const;
            
            Method const& GetMethod(UInt32 index) const;

            Method const& GetMethodViaName(Char const* name, Int32 argumentCount = -1, Type const* argumentTypes = 0) const;
            
            UInt32 GetAttributeCount() const;
            
            UInt32 GetMethodCount() const;
            
            Char8 const* GetName() const;
            
            Boolean Equals(Class const& classRecord) const;
            
            Boolean Equals(Char8 const* className) const;
            
            Boolean IsSubclass(Class const& classRecord) const;
            
            Boolean IsSubclass(Char8 const* className) const;
            
        private:
            
            Boolean ConstructImpl(std::vector< Constructor > const& constructors, UInt64* argumentTypes, UInt32 argumentCount, Constructor& out) const;
            
        private:
            
            ConstructorContainer constructors_;
            internal::Destructor destructor_;
            Char8 const* name_;
            Class const* parent_;
            Attribute* attributes_;
            Method* methods_; 
            UInt32 attributeCount_;
            UInt32 methodCount_;
        }; 
    }
}

#define RS_REFLECTION_CLASS_IMPLEMENTATION_GUARD
#include "rs/reflection/Class.ipp"
#undef RS_REFLECTION_CLASS_IMPLEMENTATION_GUARD

#endif // RS_REFLECTION_CLASS
